home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1999 April: Mac OS SDK / Dev.CD Apr 99 SDK1.toast / Development Kits / Open Transport 1.3 / Open Transport SDK / Open Tpt Protocol Developer / Samples / Configurators / TMP_Config.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-04-30  |  40.6 KB  |  1,382 lines  |  [TEXT/MPS ]

  1.  /*
  2.     File:        TMP_Config.c
  3.  
  4.     Contains:    The non-resident code for our configurator class
  5.     
  6.                 This code is not intended to implement an actual 
  7.                 working configurator.  It comes with no warranty,
  8.                 express or implied, as to it's suitability for your
  9.                 own configuration implementation.
  10. */
  11.  
  12. #ifndef __TMP_CONFIG__
  13. #include "TMP_Config.h"
  14. #endif
  15. #ifndef __OPENTPTLINKS__
  16. #include <OpenTptLinks.h>
  17. #endif
  18. #ifndef __OTSHAREDLIBS__
  19. #include "OTSharedLibs.h"
  20. #endif
  21. #ifndef __MISTREAM__
  22. #include <mistream.h>
  23. #endif
  24. #ifndef __TIHDR__
  25. #include <tihdr.h>
  26. #endif
  27.  
  28. #ifndef __FILES__
  29. #include <Files.h>
  30. #endif
  31.  
  32. #if TMPCONFIG_USES_ASLM
  33. #include <LibraryManagerUtilities.h>
  34. #else
  35. #include <CodeFragments.h>
  36. #endif
  37.  
  38. /*******************************************************************************
  39. ** Forward declarations
  40. ********************************************************************************/
  41.  
  42. OSStatus    TMPCreateStream(TOTConfigurator*, OTConfiguration*, OTOpenFlags, OTNotifyProcPtr, void*);
  43. OSStatus    TMPConfigure(TOTConfigurator*, OTConfiguration*);
  44. void        TMPHandleSystemEvent(TOTConfigurator*, OTEventCode, OTResult, void*);
  45.  
  46. static void            TMPCloseUnusedConfigurations(TOTConfigurator*);
  47. static void            DestroyAConfiguration(AConfiguration*, OSStatus, boolean_p);
  48.  
  49. static Boolean        InitAConfiguration(AConfiguration*);
  50. static void            DeleteAConfiguration(AConfiguration*);
  51. static OTResult        TMPRemoveInterface(OTPortRef, OTResult, boolean_p);
  52. static OSStatus        ConfigureNetworkLayer(OTConfiguration*);
  53. static OSStatus        ConfigureDefaultLink(OTConfiguration*);
  54. static void            CloseAConfiguration(AConfiguration* aCfig);
  55. static pascal void    CreateNetworkLayer(OTStateMachine*);
  56. static pascal void    OpenAndPush(OTStateMachine*);
  57. static void            RemoveInterface(OTPortRef, OTResult, Boolean doneDeal);
  58. static Boolean        ProcessOpenInfo(OTLink* link);
  59.  
  60.  
  61. /*
  62.  * This is our process proc we use for timers and system tasks to unload
  63.  * configurations.
  64.  */
  65. pascal void  MyConfigProcessProc(void*);
  66.  
  67. /*******************************************************************************
  68. ** Globals
  69. ********************************************************************************/
  70. /*
  71.  * Our global variables
  72.  */
  73. #if GENERATING68K
  74.     MyGlobal                gTMPGlobal;
  75. #else
  76.     extern MyGlobal            gTMPGlobal;
  77. #endif
  78. /*
  79.  * Our configurator object, so that we can access it from our non-C++ state
  80.  * machines functions
  81.  */
  82. static TMPConfigurator*            gConfigData = NULL;
  83. static TOTConfigurator*            gConfigor     = NULL;
  84. /*
  85.  * The file spec for our library so that we can get resources
  86.  * out of it - real handy for OTNotifyUser.
  87.  */
  88. static FSSpec                    gMyFile;
  89. /*
  90.  * Our list of protocols.
  91.  */
  92. static char* gList[] = { kProtocolList, 0 };
  93. /*
  94.  * Size of preference structures for our various protocol
  95.  * preferences.
  96.  */
  97. static UInt16    gPrefLens[] =
  98. {
  99.     sizeof(Prot1Prefs),
  100.     sizeof(Prot2Prefs),
  101.     sizeof(Prot3Prefs)
  102. };
  103.  
  104. /*******************************************************************************
  105. ** MyEventProc
  106. **
  107. ** This procedure handles events from our control streams
  108. **
  109. ** This is our own function, and nothing outside our module knows about it.
  110. **
  111. ** NOTE: For Mac OS 8, this routine is always called in the "master" controller
  112. ** library (the one that created the control streams).
  113. ********************************************************************************/
  114.  
  115. pascal void MyEventProc(void* ref, OTEventCode code, OTResult, void* cookie);
  116.  
  117. pascal void MyEventProc(void* ref, OTEventCode code, OTResult result, void* cookie)
  118. {
  119.     #pragma unused(cookie, result)
  120.     /*
  121.      * The reverence is the AConfiguration that corresponds to the control stream
  122.      * that is sending us the event.  Remember, this is an event directly from a
  123.      * stream, not from a provider, so the events are much lower-level events.  This
  124.      * code duplicates what the provider infrastructure does to process incoming
  125.      * stream messages.
  126.      */
  127.     AConfiguration* aCfig = (AConfiguration*)ref;
  128.     /*
  129.      * If it's a SIGPOLL event, we want to read the event off of the
  130.      * head of the stream.
  131.      */
  132.     if ( code == kSIGNALEVENT + SIGPOLL )
  133.     {
  134.         OTBuffer*    buf;
  135.         /*
  136.          * We keep reading the streamhead until there's nothing on it!
  137.          */
  138.         while ( true )
  139.         {
  140.             /*
  141.              * You could use "OTGetMessage" to get the message off of the stream,
  142.              * or you can use our ReadMessage API
  143.              */
  144.             OTReadInfo    rpBuf;
  145.             
  146.             rpBuf.fType        = kOTAnyMsgType;
  147.             rpBuf.fCommand    = 0;
  148.             
  149.             buf = OTReadMessage(aCfig->fCtlStream, &rpBuf);
  150.             /*
  151.              * If there's nothing on the stream - get out of here
  152.              */
  153.             if ( buf == NULL )
  154.                 break;
  155.  
  156.             if ( (buf->fType != M_PROTO && buf->fType != M_PCPROTO) ||
  157.                  buf->fLen != sizeof(T_event_ind) || 
  158.                  ((T_event_ind*)buf->fData)->PRIM_type != T_EVENT_IND )
  159.             {
  160.                 DebugStr("\pMyEventProc - unexpected buffer read");
  161.             }
  162.             else
  163.             {
  164.                 /*
  165.                  * Let's notify the user about certain events.  We have our file spec
  166.                  * stored in gMyFile, and we can provide the STR# resource ID and
  167.                  * index number (1-based, just like GetIndString).  The other 2 parameters
  168.                  * can be used like ParamText, supplying strings to substitute into
  169.                  * ^0 and ^1 characters in the resource string.
  170.                  */
  171.                 switch ( ((T_event_ind*)buf->fData)->EVENT_code )
  172.                 {
  173.                     case kMyEvent1:
  174.                         OTNotifyUser(&gMyFile, kMyResourceID, kEvent1ID, NULL, NULL);
  175.                         break;
  176.                         
  177.                     case kMyEvent2:
  178.                         OTNotifyUser(&gMyFile, kMyResourceID, kEvent2ID, NULL, NULL);
  179.                         break;
  180.                         
  181.                     case kMyNoClientEvent:
  182.                         /*
  183.                          * Here, our control stream is telling us that all of our clients have
  184.                          * gone away and that we can schedule an unload
  185.                          */
  186.                         if ( OTCompareAndSwap8(kIsInUse, kIsScheduled, &aCfig->fStatus) )
  187.                         {
  188.                             /*
  189.                              * Schedule ourselves to unload after kMyUnloadTimeout milliseconds. 
  190.                              * You can also schedule yourself to unload by just scheduling the
  191.                              * system task, and the unload will occur at the next System Task.
  192.                              * It is a horrible idea to unload yourself right now, because we're still
  193.                              * in the code that will be unloaded (and we're not at system task time).
  194.                              * However, you could call your "scheduleUnload" vector in the shared structure,
  195.                              * since that function will schedule a system task.  We prefer to put in a
  196.                              * time delay here so that we don't thrash ourselves to death.
  197.                              */
  198.                             OTScheduleTimerTask(aCfig->fTimerTask, kMyUnloadTimeout);
  199.                         }
  200.                         
  201.                 }
  202.             }
  203.             /*
  204.              * When we're all done, give the buffer back to Open Transport
  205.              */
  206.             OTReleaseBuffer(buf);
  207.         }
  208.     }
  209.     else
  210.     {
  211.         DebugStr("\pMyEventProc - unexpected event");
  212.     }
  213. }
  214.  
  215. /*******************************************************************************
  216. ** AConfiguration routines
  217. ********************************************************************************/
  218.  
  219. static Boolean InitAConfiguration(AConfiguration* aCfig)
  220. {
  221.     if ( aCfig == NULL )
  222.         return false;
  223.     aCfig->fCtlStream                = kOTInvalidStreamRef;
  224.     aCfig->fHelperStream            = kOTInvalidStreamRef;
  225.     aCfig->fLinkID                    = kOTInvalidPortRef;
  226.     aCfig->fOurID                    = kOTInvalidPortRef;
  227.     aCfig->fStatus                    = kIsBeingCreated;
  228.     aCfig->fPrefs                    = NULL;
  229.     aCfig->fNetworkName[0]            = 0;
  230.     /*
  231.      * This cannot be moved to the TMP_CreateConfig file, because we need the pointers
  232.      * to the MyConfigProcessProc to be real pointers to real routines, not ASLM or CFM
  233.      * stubs (otherwise we'll be calling through glue that goes "bye-bye" when the
  234.      * CreateConfig library unloads.
  235.      */
  236.     aCfig->fTimerTask                = OTCreateTimerTask(MyConfigProcessProc, aCfig);
  237.     aCfig->fSystemTask                = OTCreateSystemTask(MyConfigProcessProc, aCfig);
  238.     return aCfig->fTimerTask != 0 && aCfig->fSystemTask != 0;
  239. }
  240.  
  241. static void DeleteAConfiguration(AConfiguration* aCfig)
  242. {
  243.     /*
  244.      * These functions act correctly if the vars are 0, so let's just call
  245.      * them rather than testing for 0
  246.      */
  247.     OTDestroyTimerTask(aCfig->fTimerTask);
  248.     OTDestroySystemTask(aCfig->fSystemTask);
  249.     OTFreeSharedClientMem(aCfig);
  250. }
  251.  
  252. /*******************************************************************************
  253. ** MyConfigProcessProc
  254. **
  255. ** This is our own function, and nothing outside our module knows about it.
  256. ********************************************************************************/
  257.  
  258.     /*
  259.      * A helpful routine to use when searching our lists to see if the link
  260.      * passed in (which is the link of an "AConfiguration" object) matches
  261.      * the portref passed in.  We add the extra piece of logic that if the
  262.      * ref is kOTInvalidPortRef, it matches all configurations.
  263.      */
  264.     static Boolean FindMyConfig(const void* ref, OTLink* link)
  265.     {
  266.         if ( OTGetLinkObject(link, AConfiguration, fMyLink)->fStatus == kIsUnused )
  267.             return false;
  268.         if ( *(const OTPortRef*)ref == kOTInvalidPortRef )
  269.             return true;
  270.         return OTGetLinkObject(link, AConfiguration, fMyLink)->fLinkID == *(const OTPortRef*)ref;
  271.     }
  272.     /*
  273.      * This function finds any configuration that depends on the OTPortRef.  In the prior
  274.      * function, it must be exactly the OTPortRef.
  275.      */
  276.     static Boolean FindMyConfigByPort(const void* ref, OTLink* link)
  277.     {
  278.         if ( OTGetLinkObject(link, AConfiguration, fMyLink)->fStatus == kIsUnused )
  279.             return false;
  280.         if ( *(const OTPortRef*)ref == kOTInvalidPortRef )
  281.             return true;
  282.         return OTIsDependentPort(OTGetLinkObject(link, AConfiguration, fMyLink)->fLinkID,
  283.                                  *(const OTPortRef*)ref);
  284.     }
  285.  
  286. pascal void MyConfigProcessProc(void* arg)
  287. {
  288.     OTResult        result = 0;
  289.     AConfiguration* aCfig = (AConfiguration*)arg;
  290.     /*
  291.      * If our unload cancelled, just forget it!
  292.      */
  293.     if ( aCfig->fStatus != kIsScheduled )
  294.         return;
  295.     /*
  296.      * If we're not at system task time, schedule a system task
  297.      */
  298.     if ( !OTCanMakeSyncCall() )
  299.     {
  300.         OTScheduleSystemTask(aCfig->fSystemTask);
  301.         return;
  302.     }
  303.  
  304.     /*
  305.      * If we can't "enter the gate", reschedule for retry.  We need to enter
  306.      * the gate, because we're about to commit to unloading.  If some interrupt
  307.      * code should decide to asynchronously open an endpoint, we want it to wait
  308.      * on the queue until we're all done tearing this down, just in case it's a
  309.      * request for the same link (We have to commit sometime, and we can always
  310.      * run into this situation).
  311.      */
  312.     while ( !OTEnterGate(&gConfigData->fGate, NULL) )
  313.     {
  314.         if ( !OTLeaveGate(&gConfigorData->fGate )
  315.         {
  316.             OTScheduleTimerTask(aCfig->fTimerTask, kMyUnloadTimeout);
  317.             return;
  318.         }
  319.     }
  320.     /*
  321.      * If we're still schedule to unload, we're now committed
  322.      */
  323.     if ( aCfig->fStatus == kIsScheduled )
  324.     {
  325.         /*
  326.          * Remove ourself from the list of configurations, and destroy
  327.          * the configuration.
  328.          */
  329.         (void)OTRemoveLink(&gConfigData->fGlobal->fConfigs, &aCfig->fMyLink);
  330.         DestroyAConfiguration(aCfig, kOTNoError, true);
  331.         /*
  332.          * If there are no more configurations, and there are no outstanding
  333.          * open requests, we can shut down
  334.          */
  335.         if ( gConfigData->fGlobal->fConfigs.fHead == NULL && gConfigData->fList == NULL )
  336.         {
  337.             OTLeaveGate(&gConfigData->fGate);
  338.             TMPCloseUnusedConfigurations(gConfigor);
  339.             return;
  340.         }
  341.     }
  342.     OTLeaveGate(&gConfigData->fGate);
  343. }
  344.  
  345. /*******************************************************************************
  346. ** OTCreateMyConfigurator
  347. **
  348. ** This is the function our resident guy calls to create the configurator.
  349. **
  350. ** This function is known only to our resident code.
  351. ********************************************************************************/
  352.  
  353.     static void OTInitMyConfigurator(TMPConfigurator* cfig)
  354.     {
  355.         cfig->fGlobal                = &gTMPGlobal;
  356.         cfig->fShared                = NULL;
  357.         cfig->fList                    = NULL;
  358.         cfig->fShuttingDown            = false;
  359.         cfig->fDontUnload            = false;
  360.         OTInitGate(&cfig->fGate, ProcessOpenInfo);
  361.     }
  362.  
  363. OSStatus OTCreateMyConfigurator(MySharedStruct* info)
  364. {
  365.     OSStatus            err = kOTNoError;
  366.     TMPConfigurator*    data = (TMPConfigurator*)OTAllocSharedClientMem(sizeof(TMPConfigurator*));
  367.     TOTConfigurator*    cfig;
  368.     
  369.     if ( data == NULL )
  370.         return kENOMEMErr;
  371.         
  372.     OTInitMyConfigurator(data);
  373.     
  374.     cfig = OTNewConfigurator(data, TMPConfigure, TMPCreateStream, TMPHandleSystemEvent);
  375.     if ( cfig == NULL )
  376.     {
  377.         OTFreeSharedClientMem(data);
  378.         return kENOMEMErr;
  379.     }
  380.     /*
  381.      * Create a system task for us to go through our teardown logic.
  382.      */
  383.     info->systemTask = OTCreateSystemTask(info->unloadProc, NULL);
  384.     /*
  385.      * If everything's cool, store our configurator off into our global,
  386.      * and copy it into the shared structure's "cfig" field.  Also,
  387.      * keep a copy of the fShared structure so that we can reference
  388.      * the unload vector.
  389.      * Otherwise, delete the configurator and return an error.
  390.      */
  391.     if ( info->systemTask == 0 )
  392.     {
  393.         OTFreeSharedClientMem(data);
  394.         OTDeleteConfigurator(cfig);
  395.         return kENOMEMErr;
  396.     }
  397.     gConfigor        = cfig;
  398.     gConfigData        = data;
  399.     /*
  400.      * Give the resident guy a pointer to our configurator.  It doesn't really
  401.      * need it, but you never know.
  402.      */
  403.     info->cfig        = cfig;
  404.     /*
  405.      * Pick up the shared structure pointer.
  406.      */
  407.     data->fShared    = info;
  408.     
  409.     return kOTNoError;
  410. }
  411.  
  412. /*******************************************************************************
  413. ** ProcessATOpenInfo
  414. **
  415. ** This routine is called by the gate code whenever we need to process
  416. ** a DDP creation
  417. ********************************************************************************/
  418.  
  419.     void CreateStreamDoneProc(void* unUsed)
  420.     {
  421.         #pragma unused (unUsed)
  422.         
  423.         OTLeaveGate(&gConfigData->fGate);
  424.     }
  425.  
  426. static Boolean ProcessOpenInfo(OTLink* link)
  427. {
  428.     TMPOpenInfo* info = OTGetLinkObject(link, TMPOpenInfo, fLink);
  429.     if ( gConfigData->fShuttingDown )
  430.     {
  431.         info->fStateMachine->fResult = kENXIOErr;
  432.         OTSMPopCallback(info->fStateMachine);
  433.         OTSMComplete(info->fStateMachine);
  434.         return true;
  435.     }
  436.     OTSMInstallCompletionProc(info->fStateMachine, CreateStreamDoneProc, NULL);
  437.     if ( info->fToPush == NULL )
  438.         OTSMCallStateProc(info->fStateMachine, CreateNetworkLayer, 0);
  439.     else
  440.         OTSMCallStateProc(info->fStateMachine, OpenAndPush, 0);
  441.     /*
  442.      * We must return false even if we're already done, because the state machine
  443.      * will call our completion proc, which will call LeaveGate().  If we return
  444.      * true, we'll be inside the gate executing twice, which would be 
  445.      * embarrassing.
  446.      */
  447.     return false;
  448. }
  449.  
  450. /*******************************************************************************
  451. ** HandleSystemEvent
  452. **
  453. ** Called by the system when something notable occurs
  454. ********************************************************************************/
  455.  
  456. void TMPHandleSystemEvent(TOTConfigurator* cfig, OTEventCode event, OTResult result,
  457.                           void* cookie)
  458. {
  459.     OTLink*        link;
  460.     /*
  461.      * Of course, we can also use our global variables here - it had better be the same!
  462.      */
  463.     TMPConfigurator* data = (TMPConfigurator*)OTGetConfiguratorUserData(cfig);
  464.     
  465.     switch ( event )
  466.     {
  467.         case kOTSystemSleep:
  468.             /*
  469.              * For sleep, we've adopted the same policy as shutdown for AppleTalk and
  470.              * TCP/IP just to keep things simple.  AppleTalk has to because it can't
  471.              * defend it's node address while it is asleep.  If TCP/IP is not using
  472.              * MacIP, it could actually stay alive, but for now.....
  473.              */
  474.         case kOTSystemShutdown:
  475.         {
  476.             /*
  477.              * Tell ourselves that we're shutting down
  478.              */
  479.             data->fShuttingDown = true;
  480.             /*
  481.              * Lock the gate, in case we're not already inside it, so that no more
  482.              * opens start up
  483.              */
  484.             OTEnterGate(&data->fGate, NULL);
  485.             /*
  486.              * Now destroy all the configurations
  487.              */
  488.  
  489.             while ( (link = OTRemoveFirst(&data->fGlobal->fConfigs)) != NULL )
  490.             {
  491.                 AConfiguration* aCfig = OTGetLinkObject(link, AConfiguration, fMyLink);
  492.                 DestroyAConfiguration(aCfig, (OTResult)event, false);
  493.             }
  494.             OTLeaveGate(&data->fGate);
  495.             data->fShuttingDown = false;
  496.             break;
  497.         }
  498.         
  499.         case kOTPortDisabled:
  500.             /*
  501.              * If a port has been disabled, call our TMPRemoveInterface function so that
  502.              * if we depend on the disabled port, we blow the configuration away.
  503.              * NOTE: The cookie for this event is the OTPortRef that's gone.  We
  504.              * Set "doneDeal" to true because typically, the port is history by the
  505.              * time we get this notification.
  506.              */
  507.             TMPRemoveInterface((OTPortRef)cookie, result, true);
  508.             break;
  509.     }
  510. }
  511.  
  512. /*******************************************************************************
  513. ** ConfigureDefaultLink
  514. **
  515. ** You probably don't need this method if you're configuring a link layer, but it's
  516. ** a placehold for protocols that might have the concept of a "default link" in
  517. ** their prefs somewhere.  AppleTalk currently uses pRAM.  TCP/IP currently
  518. ** does not allow anything but a default link, and it's retrieved from the 
  519. ** preferences stored in the preferences file.
  520. **
  521. ** This is our own function, and nothing outside our module knows about it.
  522. ********************************************************************************/
  523.  
  524. OSStatus ConfigureDefaultLink(OTConfiguration* cfig)
  525. {
  526.     OSStatus        err;
  527.     OTPortRecord    record;
  528.     /*
  529.      * In this routine, you would determine what you're default link should be, 
  530.      * push it as a child, and return OTConfigureChildren.  As an example,
  531.      * we try to find a motherboard ethernet device and use it.
  532.      */
  533.     if ( OTFindPortByRef(&record, OTCreatePortRef(kOTMotherboardBus, kOTEthernetDevice, 0, 0)) )
  534.     {
  535.         if ( OTCfigPushNewSingleChild(cfig, record.fPortName, &err) == NULL )
  536.             return err;
  537.         return OTConfigureChildren(cfig);
  538.     }
  539.     return kOTNotSupportedErr;
  540. }
  541.  
  542. /*******************************************************************************
  543. ** ConfigureNetworkLayer
  544. **
  545. ** You probably don't need this method if you're configuring a link layer.  It's
  546. ** a placeholder because often, the network layer of a protocol is really a
  547. ** streams driver rather than a pushable module, so we need a single copy
  548. ** of the network layer that we can clone for clients (see TMP_CreateConfig.cp
  549. ** for how this is actually done).
  550. **
  551. ** This is our own function, and nothing outside our module knows about it.
  552. ********************************************************************************/
  553.  
  554. static OSStatus ConfigureNetworkLayer(OTConfiguration* cfig)
  555. {
  556.     OSStatus            err;
  557.     OTConfiguration*    kid;
  558.     /*
  559.      * Our network layer can only have 1 thing underneath it.
  560.      */
  561.     if ( OTCfigGetChild(cfig, 1) != NULL )
  562.         return kOTNotSupportedErr;
  563.  
  564.     kid = OTCfigGetChild(cfig, 0);
  565.     /*
  566.      * If we have no child, configure the default link
  567.      */
  568.     if ( kid == NULL )
  569.         return ConfigureDefaultLink(cfig);
  570.     /*
  571.      * Configure our children so we can see what's really going on.
  572.      */
  573.     err = OTConfigureChildren(cfig);
  574.     
  575.     if ( err != kOTNoError )
  576.         return err;
  577.     /*
  578.      * Just in case our child changed, pick it up again.
  579.      */
  580.     kid = OTCfigGetChild(cfig, 0);
  581.     /*
  582.      * If the kid's not a port - bummer
  583.      */
  584.     if ( !OTCfigIsPort(kid) )
  585.         return kOTNotSupportedErr;
  586.     /*
  587.      * Let's see if it's a port we don't support.  This code is the way AppleTalk
  588.      * used to determine if the port is usable or not.  Your mileage may vary.
  589.      */
  590.     switch ( OTGetDeviceTypeFromPortRef(OTCfigGetPortRef(kid)) )
  591.     {
  592.         /*
  593.          * Devices we know we don't support
  594.          */
  595.         case kOTSerialDevice:
  596.         case kOTModemDevice:
  597.         case kOTISDNDevice:
  598.         case kOTATMDevice:
  599.         case kOTATMSNAPDevice:
  600.         case kOTMDEVDevice:
  601.             err = kOTNotSupportedErr;
  602.             break;
  603.         /*
  604.          * Devices that have special logic
  605.          */
  606.         case kOTEthernetDevice:
  607.         case kOTFastEthernetDevice:
  608.         {
  609.             /*
  610.              * For ethernet - make sure the port supports 8022 framing
  611.              */
  612.             OTPortRecord    record;
  613.             if ( !OTFindPort(&record, OTCfigGetProviderName(kid)) || !(record.fCapabilities & kOTFraming8022) )
  614.                 err = kOTNotSupportedErr;
  615.             break;
  616.         }
  617.         /*
  618.          * We'll assume we can work with any other DLPI driver.  This may not be true,
  619.          * but we're willing to give it a shot.  In OT 1.5, AppleTalk will look for
  620.          * a configuration library that will contain some functions to help us
  621.          * configure over unfamiliar links.
  622.          */
  623.         default:
  624.             if ( !(OTCfigGetInstallFlags(kid) & kOTPortIsDLPI) )
  625.                 err = kOTNotSupportedErr;
  626.             break;
  627.     }
  628.     return err;
  629. }
  630.  
  631. /*******************************************************************************
  632. ** Configure
  633. **
  634. ** This routine is used to specify the configuration of our object. It is called
  635. ** by the Open Transport infrastructure when a client opens a provider that your
  636. ** "CanConfigure" function returned true for.
  637. ********************************************************************************/
  638.  
  639. OSStatus TMPConfigure(TOTConfigurator* cfigor, OTConfiguration* cfig)
  640. {
  641.     #pragma unused(cfigor)
  642.     
  643.     const char*            name = OTCfigGetProviderName(cfig);
  644.     int                    index = -1;
  645.     OSStatus            err;
  646.     OTConfiguration*    kid;
  647.     
  648.     /*
  649.      * Find which layer we're configuring.  This call cannot fail unless
  650.      * someone manually calls us, since we know that "CanConfigure" passed.
  651.      */
  652.     while ( gList[++index] != NULL )
  653.     {
  654.         if ( OTStrEqual(name, gList[index]) )
  655.             break;
  656.     }
  657.     /*
  658.      * Now, do some sanity checking.
  659.      */
  660.     kid = OTCfigGetChild(cfig, 0);
  661.     /*
  662.      * Obviously, modify this test if not appropriate.  For links, usually
  663.      * the test is for "kid" being NULL.
  664.      */
  665.     if ( OTCfigGetChild(cfig, 1) != NULL )
  666.     {
  667.         return kENXIOErr;
  668.     }
  669.     /*
  670.      * If you're a link, you don't need this.  For a protocol, let's assume
  671.      * the kProt1 is your network layer and kProt2 and kProt3 are protocols you
  672.      * could push on top
  673.      */
  674.     switch ( index )
  675.     {
  676.         default:
  677.             return kENXIOErr;
  678.             
  679.         case kProt1ID:
  680.             return ConfigureNetworkLayer(cfig);
  681.         
  682.         case kProt2ID:
  683.         case kProt3ID:
  684.             /*
  685.              * If we don't have a child, or it's not our network layer,
  686.              * push a copy of our network layer as our child, then
  687.              * call OTConfigureChildren to complete the configuration.
  688.              */
  689.             if ( kid == NULL || !OTStrEqual(OTCfigGetProviderName(kid), gList[kProt1ID]) )
  690.             {
  691.                 /*
  692.                  * "Push" a copy of our protocol1 underneath us as a child.
  693.                  * If it returns NULL, an error occured.
  694.                  */
  695.                 if ( OTCfigPushNewSingleChild(cfig, gList[kProt1ID], &err) == NULL )
  696.                     return err;
  697.             }
  698.             /*
  699.              * Configure our children.  This will recursively call us to 
  700.              * configure our network layer.
  701.              */
  702.             return OTConfigureChildren(cfig);
  703.                 
  704.     }
  705. }
  706.  
  707. /*******************************************************************************
  708. ** OpenAndPush
  709. **
  710. ** This procedure is used for asynchronous opens, where we have to Open the module
  711. ** below us, then push a module on top of it.
  712. **
  713. ** Using the OTStateMachine object allows us to asynchronously do common
  714. ** stream functions in a way that looks pseudo-synchronous.  Each of these
  715. ** functions returns a Boolean that's true if the function is already complete, and
  716. ** false if the function is not yet complete.  If the function is not yet complete,
  717. ** just return (but have the "next" state set up before calling the function or
  718. ** bad things could happen).  The state machine will call back in to your function
  719. ** when it finally completes.  If it is complete, typically a continue is executed
  720. ** to reenter the switch statement.  In all cases, the fResult field will have
  721. ** the result value from the function.  DO NOT FORGET that IOCTL functions can
  722. ** return positive values that are not errors, so be sure to test for "less than"
  723. ** 0 if the function you exectued was an IOCTL.
  724. **
  725. ** This is our own function, and nothing outside our module knows about it.
  726. ********************************************************************************/
  727.  
  728. static pascal void OpenAndPush(OTStateMachine* sm)
  729. {    
  730.     TMPOpenInfo* info = (TMPOpenInfo*)OTSMGetClientData(sm);
  731.     
  732.     while ( true )
  733.     {
  734.         switch ( OTSMGetState(sm) )
  735.         {
  736.             case 0:
  737.             {
  738.                 OTSMSetState(sm, 1);
  739.                 /*
  740.                  * If it's our own network layer we're opening, invoke our CreateNetworkLayer
  741.                  * state machine function.  Otherwise, let's call CreateStream.
  742.                  */
  743.                 if ( OTStrEqual(OTCfigGetProviderName(info->fCfig), gList[kProt1ID]) )
  744.                 {
  745.                     /*
  746.                      * This code is really for Mac OS 8, where the control stream has to be
  747.                      * created in the master configurator.  If we're the master configurator,
  748.                      * we just invoke our state machine to do the plumbing.  If we're not,
  749.                      * we use the OTSMCreateControlStream function to get the data to our
  750.                      * master configurator to do the plumbing.
  751.                      */
  752.                     if ( OTIsMasterConfigurator(gConfigor) )
  753.                     {
  754.                         if ( !OTSMCallStateProc(sm, CreateNetworkLayer, 0))
  755.                             return;
  756.                     }
  757.                     else
  758.                     {
  759.                         if ( !OTSMCreateControlStream(sm, info->fCfig, gConfigor) )
  760.                             return;
  761.                     }
  762.                 }
  763.                 else
  764.                 {
  765.                     if ( !OTSMCreateStream(sm, info->fCfig, info->fOpenFlags) )
  766.                         return;
  767.                 }
  768.                 /*
  769.                  * If we fall through, then the routine we called finished synchronously, so we can
  770.                  * go on to the next state.
  771.                  */
  772.                 continue;
  773.             }
  774.             
  775.             case 1:
  776.             {
  777.                 OTSMSetState(sm, 2);
  778.                 /*
  779.                  * If an error occurred opening the stream, break and complete
  780.                  * to the client.  Notification to the client will consist of the
  781.                  * "fCode", "fResult", and "fCookie" fields.
  782.                  */
  783.                 if ( sm->fResult != kOTNoError )
  784.                 {
  785.                     sm->fCode    = kStreamOpenEvent;
  786.                     sm->fCookie    = 0;
  787.                     break;
  788.                 }
  789.                 /*
  790.                  * Save the stream we're working on.
  791.                  */
  792.                 info->fTheStream = (StreamRef)sm->fCookie;
  793.                 /*
  794.                  * Invoke the IOCTL to push the module we're supposed to push
  795.                  */
  796.                 if ( !OTSMIoctl(sm, info->fTheStream, I_PUSH, (long) OTCfigGetProviderName(info->fToPush)) )
  797.                     return;
  798.                 /*
  799.                  * If we fall through, then the routine we called finished synchronously, so we can
  800.                  * go on to the next state.
  801.                  */
  802.                 continue;
  803.             }
  804.                 
  805.             case 2:
  806.             {
  807.                 OTSMSetState(sm, 3);
  808.                 /*
  809.                 * Remember, it was an IOCTL, so fResult could be a positive number.
  810.                 */
  811.                 if ( sm->fResult >= 0 )
  812.                 {
  813.                     /*
  814.                      * Set up the code, result, and cookie to complete to the client. 
  815.                      */
  816.                     sm->fCode    = kStreamOpenEvent;
  817.                     sm->fCookie    = info->fTheStream;
  818.                     sm->fResult    = kOTNoError;
  819.                     break;
  820.                 }
  821.                 /*
  822.                  * An error occurred - close the original stream
  823.                  */
  824.                 OTStreamClose(info->fTheStream);
  825.                 break;
  826.             }
  827.         }
  828.         break;
  829.     }
  830.     /*
  831.      * Complete to the original client
  832.      */
  833.     OTSMPopCallback(info->fStateMachine);
  834.     OTSMComplete(info->fStateMachine);
  835. }
  836.  
  837. /*******************************************************************************
  838. ** CreateStream
  839. **
  840. ** This function must create the stream specified in the OTConfiguration.  It is
  841. ** called when a client creates a provider, your "CanConfigure" function returned
  842. ** true for this configuration, and your "Configure" function return kOTNoError
  843. ** for the configuration, after modifying it to suit your taste.
  844. ********************************************************************************/
  845.  
  846. OSStatus TMPCreateStream(TOTConfigurator* cfigor, 
  847.                          OTConfiguration* cfig, OTOpenFlags flags,
  848.                          OTNotifyProcPtr proc, void* contextPtr)
  849. {
  850.     TMPConfigurator*    data = (TMPConfigurator*)OTGetConfiguratorUserData(cfigor);
  851.     const char*            name = OTCfigGetProviderName(cfig);
  852.     TMPOpenInfo*        info;
  853.     OTStateMachine*        sm;
  854.     int                    index = -1;
  855.     /*
  856.      * We anticipate have 2 levels of state machine invocation (i.e. one state 
  857.      * machine invoking another).  That's what the kOTSMBufferSize(2) is for.
  858.      * If you give this too small a number, you'll trounce memory if you invoke
  859.      * state machines too deeply.
  860.      */
  861.     char            stakInfo[sizeof(TMPOpenInfo) + kOTSMBufferSize(2)];
  862.     /*
  863.      * If we're shutting down, return an immediate error
  864.      */
  865.     if ( data->fShuttingDown )
  866.         return kENXIOErr;
  867.     
  868.     /*
  869.      * Find which layer we're configuring.  This routine is also never called without having
  870.      * gone through "CanConfigure" and "Configure", so we know this is an OTConfiguration we
  871.      * can live with, and that the top layer points to one of our protocols.
  872.      */
  873.     while ( gList[++index] != NULL )
  874.     {
  875.         if ( OTStrEqual(name, gList[index]) )
  876.             break;
  877.     }
  878.     
  879.     /*
  880.      * We create a stream state machine.  It will be created using the stack buffer for
  881.      * synchronous calls, and the memory will be allocated for asynchronous calls.
  882.      */
  883.     sm = OTCreateStateMachine(stakInfo, sizeof(stakInfo), sizeof(TMPOpenInfo),
  884.                               proc, contextPtr);
  885.                                 
  886.     if ( sm == NULL )
  887.         return kENOMEMErr;
  888.         
  889.     info = (TMPOpenInfo*)OTSMGetClientData(sm);
  890.     /*
  891.      * Save the open flags.  STREAMS doesn't really use them, but you never know.....
  892.      */
  893.     info->fOpenFlags = flags;
  894.     info->fStateMachine = sm;
  895.     /*
  896.      * If the index is not kProt1ID, set the fToPush configuration
  897.      */
  898.     if ( index != kProt1ID )
  899.     {
  900.         OTConfiguration* kid = OTCfigGetChild(cfig, 0);
  901.         if ( kid == NULL )
  902.             return kENXIOErr;
  903.         info->fCfig = kid;
  904.         info->fToPush = cfig;
  905.     }
  906.     /*
  907.      * Enter the gate to execute the code.  The gate will only execute one open
  908.      * at a time and keep everything synchronized nicely.
  909.      */
  910.     OTEnterGate(&gConfigData->fGate, &info->fLink);
  911.     /*
  912.      * Always call "OTSMReturnToCaller" here.  If the original call was synchronous,
  913.      * OTSMReturnToCaller will wait for completion. Otherwise, it will set up
  914.      * everything necessary to call back the original client when things do 
  915.      * complete.
  916.      */
  917.     return OTSMReturnToCaller(sm);
  918. }
  919.  
  920. /*******************************************************************************
  921. ** CloseAConfiguration
  922. ** This function just closes down all the streams belonging to the configuration.
  923. **
  924. ** This is our own function, and nothing outside our module knows about it.
  925. ********************************************************************************/
  926.  
  927. void CloseAConfiguration(AConfiguration* aCfig)
  928. {
  929.     //
  930.     // We set non-blocking mode because we want the close to happen right away
  931.     // without waiting for queues to drain.
  932.     //
  933.     if ( aCfig->fHelperStream)
  934.     {
  935.         OTStreamSetNonBlocking(aCfig->fHelperStream);
  936.         OTStreamClose(aCfig->fHelperStream);
  937.         aCfig->fHelperStream = NULL;
  938.     }
  939.     if ( aCfig->fCtlStream)
  940.     {
  941.         OTStreamRemoveNotifier(aCfig->fCtlStream);
  942.         OTStreamSetNonBlocking(aCfig->fCtlStream);
  943.         OTStreamClose(aCfig->fCtlStream);
  944.         aCfig->fCtlStream = NULL;
  945.     }
  946. }
  947.  
  948. /*******************************************************************************
  949. ** DestroyAConfiguration
  950. ** This function destroys the given configuration, telling all client's of this
  951. ** configuration that they're toast.
  952. **
  953. ** This is our own function, and nothing outside our module knows about it.
  954. ********************************************************************************/    
  955.  
  956. static void DestroyAConfiguration(AConfiguration* aCfig, OTResult why, boolean_p doneDeal)
  957. {
  958.     aCfig->fStatus = kIsUnused;
  959.     /*
  960.      * Destroy our tasks so they don't fire inconveniently
  961.      */
  962.     OTDestroyTimerTask(aCfig->fTimerTask);
  963.     OTDestroySystemTask(aCfig->fSystemTask);
  964.     aCfig->fTimerTask = 0;
  965.     aCfig->fSystemTask = 0;
  966.     /*
  967.      * For link configurators, you typically will call OTCloseMatchingProviders
  968.      * with a 0 for the controlMask:
  969.      *
  970.      * OTCloseMatchingProviders(0, aCfig->fLinkID, why, doneDeal).
  971.      */
  972.      OTCloseMatchingProviders(gConfigData->fGlobal->fMyMask, aCfig->fLinkID, why, doneDeal);
  973.     /*
  974.      * Close down all our control streams
  975.      */
  976.     CloseAConfiguration(aCfig);
  977.     OTFreeSharedClientMem( aCfig );
  978. }
  979.  
  980. /*******************************************************************************
  981. ** CreateNetworkLayer
  982. **
  983. ** This is our state machine function to create our network layer.  It determines
  984. ** if we already have a configuration, and also insures that we don't try to
  985. ** open the network layer reentrantly
  986. ********************************************************************************/
  987.  
  988.     typedef Boolean (*CreateNewConfigProcPtr)(TOTConfigurator*, OTStateMachine*);
  989.     
  990.     
  991. pascal void CreateNetworkLayer(OTStateMachine* sm)
  992. {
  993.     TMPOpenInfo* info = (TMPOpenInfo*)OTSMGetClientData(sm);
  994.     
  995.     while ( true )
  996.     {
  997.         switch ( OTSMGetState(sm) )
  998.         {
  999.             case 0:
  1000.             {
  1001.                 AConfiguration*        aCfig;
  1002.                 OTConfiguration*    kid;
  1003.                 OTLink*                link;
  1004.  
  1005.                 OTSMSetState(sm, 1);
  1006.                 /*
  1007.                  * Set up info for failure
  1008.                  */
  1009.                 sm->fCookie    = (void*)kOTInvalidRef;
  1010.                 sm->fCode    = kStreamOpenEvent;
  1011.                 /*
  1012.                  * If there is no child - there is something wrong!
  1013.                  */
  1014.                 kid = OTCfigGetChild(info->fCfig, 0);
  1015.                 if ( kid == NULL )
  1016.                 {
  1017.                     sm->fResult = kENXIOErr;
  1018.                     OTSMPopCallback(info->fStateMachine);
  1019.                     OTSMComplete(sm);
  1020.                     return;
  1021.                 }
  1022.                 /*
  1023.                  * Let's see if we can find a configuration that already exists.  We use the
  1024.                  * store fLinkID in the child to match configurations.  You may need a more
  1025.                  * complex test.
  1026.                  */
  1027.                 link = NULL;
  1028.                 {
  1029.                     for ( link = gConfigData->fGlobal->fConfigs.fHead; link != NULL; link = link->fNext )
  1030.                     {
  1031.                         aCfig = OTGetLinkObject(link, AConfiguration, fMyLink);
  1032.                         if ( OTCfigGetPortRef(kid) == aCfig->fLinkID )
  1033.                         {
  1034.                             break;
  1035.                         }
  1036.                     }
  1037.                 }
  1038.                 /*
  1039.                  * If we didn't find a configuration, or the configuration is
  1040.                  * currently unset, reenter the state machine  at state 2,
  1041.                  * where we create the configuration.
  1042.                  */
  1043.                 if ( link == NULL )
  1044.                 {
  1045.                     info->fConfig = NULL;
  1046.                     OTSMSetState(sm, 2);
  1047.                     continue;
  1048.                 }
  1049.                 /*
  1050.                  * Here, we have a configuration.  Deal with it appropriately
  1051.                  */
  1052.                 info->fConfig = aCfig;
  1053.  
  1054.                 switch ( aCfig->fStatus )
  1055.                 {
  1056.                     /*
  1057.                      * If it's unused - we go to state 2 to re-plumb it
  1058.                      */
  1059.                     case kIsUnused:
  1060.                         OTSMSetState(sm, 2);
  1061.                         continue;
  1062.                     /*
  1063.                      * If it's scheduled, set the state to kIsInUse, remove the configuration
  1064.                      * from the scheduler if it's there, and just go on to clone it.
  1065.                      */
  1066.                     case kIsScheduled:
  1067.                         aCfig->fStatus = kIsInUse;
  1068.                         OTCancelTimerTask(aCfig->fTimerTask);
  1069.                         OTCancelSystemTask(aCfig->fSystemTask);
  1070.                         break;
  1071.  
  1072.                     case kIsInUse:
  1073.                         break;
  1074.                 }
  1075.                 /*
  1076.                  * Just clone our network layer using the name we stored of in "fNetworkName"
  1077.                  */
  1078.                 if ( !OTSMOpenStream(sm, aCfig->fNetworkName, 0) )
  1079.                     return;
  1080.                 continue;
  1081.             }
  1082.             
  1083.             case 1:
  1084.             {
  1085.                 /*
  1086.                  * Set up completing to the client with the current fResult value.
  1087.                  */
  1088.                 OTSMPopCallback(info->fStateMachine);
  1089.                 OTSMComplete(sm);
  1090.                 return;
  1091.             }
  1092.  
  1093.         /*    -------------------------------------------------------------------------
  1094.             Here, we have either an unused configuration, or no configuration
  1095.             ------------------------------------------------------------------------- */
  1096.             
  1097.             case 2:
  1098.             {
  1099.                 AConfiguration*        aCfig = info->fConfig;
  1100.                 OTConfiguration*    kid = OTCfigGetChild(info->fCfig, 0);
  1101.             #if TMPCONFIG_USES_ASLM
  1102.                 TLibraryManager*    temp;
  1103.             #endif
  1104.  
  1105.                 OTSMSetState(sm, 3);
  1106.                 /*
  1107.                  * If we don't have a configuration, we're going to have to create one.
  1108.                  * Since creating one is in another library in this implementation, we
  1109.                  * have to be able to load libraries, or we can't go one.
  1110.                  */
  1111.                 if ( aCfig == NULL )
  1112.                 {
  1113.                     ProcPtr                proc;
  1114.                 #if TMPCONFIG_USES_ASLM
  1115.                     OSErr                osErr;
  1116.                 #endif
  1117.                     /*
  1118.                      * If we can't load libraries, conplete with an EAGAIN error to the client.
  1119.                      */
  1120.                     if ( !OTCanLoadLibraries() )
  1121.                     {
  1122.                         sm->fResult = kEAGAINErr;
  1123.                         OTSMPopCallback(info->fStateMachine);
  1124.                         OTSMComplete(sm);
  1125.                         return;
  1126.                     }
  1127.                     /*
  1128.                      * Load the library, get our function pointer to create the configuration, and 
  1129.                      * call it.
  1130.                      */
  1131.                 #if TMPCONFIG_USES_ASLM
  1132.                     temp = SetSelfAsClient();
  1133.  
  1134.                     if ( OTLoadASLMLibrary(kTMPCreateConfigASLMID) != noErr )
  1135.                     {
  1136.                         sm->fResult = kENXIOErr;
  1137.                         OTSMSetState(sm, 4);
  1138.                         continue;
  1139.                     }
  1140.                     proc = (ProcPtr)GetFunctionPointer(kTMPCreateConfigASLMID, 
  1141.                                                        "OTCreateMyConfiguration", &osErr);
  1142.                     if ( proc == 0 )
  1143.                     {
  1144.                         OTUnloadASLMLibrary(kTMPCreateConfigASLMID);
  1145.                         sm->fResult = kENXIOErr;
  1146.                         OTSMSetState(sm, 4);
  1147.                         continue;
  1148.                     }
  1149.                 #else
  1150.                     proc = (ProcPtr)OTGetCFMPointer(kTMPCreateConfigCFMID, "OTCreateMyConfiguration",
  1151.                                                     &info->fCreateID, kOTLoadACopy | kOTGetCodeSymbol);
  1152.                     if ( proc == 0 )
  1153.                     {
  1154.                         sm->fResult = kENXIOErr;
  1155.                         OTSMSetState(sm, 4);
  1156.                         continue;
  1157.                     }
  1158.                 #endif
  1159.                     info->fConfig = (AConfiguration*)OTAllocSharedClientMem(sizeof(AConfiguration));
  1160.                     if ( !InitAConfiguration(info->fConfig) )
  1161.                     {
  1162.                         sm->fResult = kENOMEMErr;
  1163.                         OTSMSetState(sm, 4);
  1164.                         continue;
  1165.                     }
  1166.  
  1167.                     if ( !(*(CreateNewConfigProcPtr)proc)(gConfigor, sm) )
  1168.                         return;
  1169.                     continue;
  1170.                 }
  1171.             }
  1172.             
  1173.             case 3:
  1174.             {
  1175.                 OTSMSetState(sm, 4);
  1176.                 /*
  1177.                  * The result of our call to OTCreateMyConfiguration is now known, so let's unload
  1178.                  * the library that did the creating of the configuration.
  1179.                  */
  1180.             #if TMPCONFIG_USES_ASLM
  1181.                 OTUnloadASLMLibrary(kTMPCreateConfigASLMID);
  1182.             #else
  1183.                 OTReleaseCFMConnection(&info->fCreateID);
  1184.             #endif
  1185.                 continue;
  1186.             }
  1187.                 
  1188.             case 4:
  1189.             {
  1190.                 /*
  1191.                  * Now, let's deal with the result of creating the configuration
  1192.                  */
  1193.                 sm->fCode    = kStreamOpenEvent;
  1194.                 sm->fCookie    = kOTInvalidRef;
  1195.                 /*
  1196.                  * If an error occured, complete this guy, run our queue, then call
  1197.                  * CheckUseCounts so that we unload if there's nothing to do.
  1198.                  */
  1199.                 if ( sm->fResult != kOTNoError )
  1200.                 {
  1201.                     OTSMPopCallback(info->fStateMachine);
  1202.                     OTSMComplete(sm);
  1203.                     return;
  1204.                 }
  1205.                 /*
  1206.                  * Now that we've created the configuration, let's go back around again and
  1207.                  * create the network layer stream using the created configuration.  This is
  1208.                  * pretty rude, but it keeps the code smaller.
  1209.                  */
  1210.                 OTSMSetState(sm, 0);
  1211.                 continue;
  1212.             }
  1213.         }
  1214.     }
  1215. }
  1216.  
  1217. /*******************************************************************************
  1218. ** RemoveInterface
  1219. **
  1220. ** This method is an API that allows the outside world to remove an interface.
  1221. ** When Open Transport closes AppleTalk, this is the function that it calls.
  1222. ********************************************************************************/
  1223.  
  1224. static OTResult TMPRemoveInterface(OTPortRef ref, OTResult why, boolean_p doneDeal)
  1225. {
  1226.     OTLink*    link;
  1227.     /*
  1228.      * We must be able to acquire the lock to remove the interface.  Otherwise, we
  1229.      * could have ugly race conditions.  Since this call is normally done by some type
  1230.      * of control panel at System Task time, this is not normally an issue.
  1231.      */
  1232.     while ( !OTEnterGate(&gConfigData->fGate, NULL) )
  1233.     { 
  1234.         if ( !OTLeaveGate(&gConfigData->fGate) )
  1235.             return kEAGAINErr;
  1236.     }
  1237.     /*
  1238.      * If we can't make a synchronous call, then when we tell clients that they're providers
  1239.      * are gone, they can't make sync calls either, so we modify doneDeal to true so the
  1240.      * clients know that.
  1241.      */
  1242.     if ( !OTCanMakeSyncCall() )
  1243.         doneDeal = true;
  1244.     /*
  1245.      * We go in a loop, because "ref" could be kOTInvalidPortRef, which asks us to
  1246.      * remove all of our interfaces.
  1247.      */
  1248.     while ( (link = OTFindAndRemoveLink(&gConfigData->fGlobal->fConfigs, FindMyConfigByPort, &ref)) != NULL )
  1249.     {
  1250.         AConfiguration* aCfig = OTGetLinkObject(link, AConfiguration, fMyLink);
  1251.         DestroyAConfiguration(aCfig, why, doneDeal);
  1252.     }
  1253.     /*
  1254.      * Since we might have destroyed all our configurations, if we've got nothing to do,
  1255.      * and the fDontUnload flag is not set, schedule our unload.
  1256.      */
  1257.     if ( gConfigData->fGlobal->fConfigs.fHead == NULL && gConfigData->fList == NULL )
  1258.     {
  1259.         /*
  1260.          * If we're supposed to ignore this call right now, do so.
  1261.          */
  1262.         if ( !gConfigData->fDontUnload )
  1263.         {
  1264.             /*
  1265.              * Tell the OT Infrastructure that your configurator object is now history
  1266.              */
  1267.             OTConfiguratorUnloaded(gConfigor);
  1268.             /*
  1269.              * Do the callback to schedule the unload process
  1270.              */
  1271.             (*gConfigData->fShared->scheduleUnloadProc)();
  1272.             OTDeleteConfigurator(gConfigor);
  1273.             gConfigor = NULL;
  1274.             gConfigData = NULL;
  1275.         }
  1276.     }
  1277.     /*
  1278.      * Release the lock, and run any new open requests that may have come in.
  1279.      */
  1280.     OTLeaveGate(&gConfigData->fGate);
  1281.     return kOTNoError;
  1282. }
  1283.  
  1284. /*******************************************************************************
  1285. ** TMPCloseUnusedConfigurations
  1286. ********************************************************************************/
  1287.  
  1288. static void TMPCloseUnusedConfigurations(TOTConfigurator* cfigor)
  1289. {
  1290.     TMPConfigurator* cf = (TMPConfigurator*)OTGetConfiguratorUserData(cfigor);
  1291.     
  1292. /*    -------------------------------------------------------------------------
  1293.      If there's nothing left - delete myself and unload from memory.
  1294.     ------------------------------------------------------------------------- */
  1295.  
  1296.     if ( cf->fGlobal->fConfigs.fHead == NULL && cf->fList == NULL )
  1297.     {
  1298.         /*
  1299.          * If we're supposed to ignore this call right now, do so.
  1300.          */
  1301.         if ( cf->fDontUnload )
  1302.             return;
  1303.         /*
  1304.          * Tell the OT Infrastructure that your configurator object is now history
  1305.          */
  1306.         OTConfiguratorUnloaded(cfigor);
  1307.         /*
  1308.          * Do the callback to schedule the unload process
  1309.          */
  1310.         (*cf->fShared->scheduleUnloadProc)();
  1311.         OTDeleteConfigurator(cfigor);
  1312.  
  1313.         return;
  1314.     }
  1315. }
  1316.  
  1317. /*******************************************************************************
  1318. ** Initialization/Termination routines
  1319. ********************************************************************************/
  1320.  
  1321. void TeardownTMPConfig()
  1322. {
  1323.     CloseOpenTransport();
  1324. }
  1325.  
  1326. #if GENERATING68K
  1327. #pragma segment A5Init
  1328. #endif
  1329.  
  1330. #if TMPCONFIG_USES_CFM
  1331.  
  1332.     pascal OSErr InitTMPConfig(CFragInitBlock* ibp)
  1333.     {
  1334.         OSStatus    err;
  1335.         
  1336.         /*
  1337.          * Create our OTFileSpec so we know where our resources are located
  1338.          */
  1339.         gMyFile = *ibp->fragLocator.u.onDisk.fileSpec;
  1340.         /*
  1341.      * Call InitOpenTransport so that Open Transport does not unload out from
  1342.      * underneath us.
  1343.      */
  1344.     if ( ( err = InitOpenTransport()) != kOTNoError )
  1345.     {
  1346.             return err;
  1347.         }
  1348.         return noErr;
  1349.     }
  1350.  
  1351. #else
  1352.  
  1353.     void InitTMPConfig(void)
  1354.     {
  1355.         OSStatus    err;
  1356.         
  1357.         /*
  1358.          * Create our OTFileSpec so we know where our resources are located
  1359.          */
  1360.         {
  1361.             TMacFileSpec* spec = (TMacFileSpec*)GetFileSpec(GetLocalLibraryFile());
  1362.             gMyFile.vRefNum = spec->fVRefNum;
  1363.             gMyFile.parID    = spec->fParID;
  1364.             gMyFile.name[0]    = spec->fName[0];
  1365.             OTMemcpy(gMyFile.name + 1, spec->fName + 1, spec->fName[0]);
  1366.         }
  1367.         /*
  1368.          * Call InitOpenTransport so that Open Transport does not unload out from
  1369.          * underneath us.
  1370.          */
  1371.         if ( ( err = InitOpenTransport()) != kOTNoError )
  1372.         {
  1373.             Fail(err, nil);
  1374.         }
  1375.     }
  1376.  
  1377. #endif
  1378.  
  1379. #if GENERATING68K
  1380. #pragma segment Main
  1381. #endif
  1382.